package com.woniuxy.productServer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniuxy.cinemaServer.exception.seat.SeatException;
import com.woniuxy.cinemaServer.model.SeatInfo;
import com.woniuxy.commons.util.Result;
import com.woniuxy.commons.util.StateUtil;
import com.woniuxy.productServer.client.CinemaClient;
import com.woniuxy.productServer.client.model.CinemaInfo;
import com.woniuxy.productServer.dao.MovieInfoMapper;
import com.woniuxy.productServer.dao.SessionTicketMapper;
import com.woniuxy.productServer.exception.cinema.CinemaException;
import com.woniuxy.productServer.exception.movieSession.MovieSessionException;
import com.woniuxy.productServer.exception.movieSession.MovieSessionExceptionCode;
import com.woniuxy.productServer.form.movieSession.MovieSessionAddForm;
import com.woniuxy.productServer.model.MovieInfo;
import com.woniuxy.productServer.model.MovieSession;
import com.woniuxy.productServer.dao.MovieSessionMapper;
import com.woniuxy.productServer.model.SessionTicket;
import com.woniuxy.productServer.param.movieSession.MovieSessionChangeParam;
import com.woniuxy.productServer.param.movieSession.MovieSessionParam;
import com.woniuxy.productServer.service.MovieSessionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.productServer.service.SessionTicketService;
import com.woniuxy.productServer.util.RedisKeyUtil;
import com.woniuxy.productServer.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 杜岷芫
 * @since 2024年03月20日
 */
@Service
public class MovieSessionServiceImpl extends ServiceImpl<MovieSessionMapper, MovieSession> implements MovieSessionService {
    @Autowired
    private MovieInfoMapper movieInfoMapper;
    @Autowired
    private CinemaClient cinemaClient;
    @Autowired
    private MovieSessionMapper movieSessionMapper;
    @Autowired
    private SessionTicketService sessionTicketService;
    @Autowired
    private SessionTicketMapper sessionTicketMapper;
    @Autowired
    private RedisUtil redisUtil;


    @Transactional
    @Override
    public void add(List<MovieSessionAddForm> param) throws Exception {
        //获取cinemaId,通过形成流，再获取相应数据生成set集合去重
        //判断放映厅
        Set<Integer> cinemaIds = param.stream().map(o -> o.getCinemaId()).collect(Collectors.toSet());
        List list = new ArrayList(cinemaIds);
        Result<List<CinemaInfo>> listResult = cinemaClient.loadCinemaByIds(list);
        if (listResult.getCode() != 200) throw new CinemaException(listResult.getCode(), listResult.getMsg());
        List<CinemaInfo> cinemaInfos = listResult.getData();
        if (cinemaInfos == null || cinemaInfos.size() != cinemaIds.size())
            throw new MovieSessionException(MovieSessionExceptionCode.MOVIE_SESSION_HAVE_CINEMA_NOT_FOUND);
        List<CinemaInfo> collect = cinemaInfos.stream().filter(o -> o.getCinemaStatus() != StateUtil.CINEMA_STATE_NORMAL).collect(Collectors.toList());
        if (collect.size() != 0)
            throw new MovieSessionException(MovieSessionExceptionCode.MOVIE_SESSION_HAVE_CINEMA_STATE_ERROR);
        //座位信息
        Result<Map<Integer, List<SeatInfo>>> seatsResult = cinemaClient.loadSeatByCinemaIds(list);
        if (seatsResult.getCode() != 200) throw new SeatException(seatsResult.getCode(), seatsResult.getMsg());
        Map<Integer, List<SeatInfo>> seatsMap = seatsResult.getData();
        SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

        //电影信息
        Set<Integer> movieIds = param.stream().map(o -> o.getMovieId()).collect(Collectors.toSet());
        List<MovieInfo> movieInfos = movieInfoMapper.selectBatchIds(movieIds);

        //排场信息
        List<MovieSession> list1 = this.list(new QueryWrapper<MovieSession>().eq("session_status", StateUtil.MOVIE_SESSION_STATE_NORMAL)
                .in("cinema_id", cinemaIds)
                .gt("session_endtime", DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss")));
        param.forEach(o->{
            list1.add(BeanUtil.toBean(o,MovieSession.class));
        });

        //
        HashMap<Integer, CinemaInfo> cinemaMap = new HashMap<>();
        for (CinemaInfo cinemaInfo : cinemaInfos) {
            cinemaMap.put(cinemaInfo.getCinemaId(),cinemaInfo);
        }
        for (MovieSessionAddForm form : param) {
            //座位
            //如果不传座位id，则该放映厅全部
            if (!(form.getSeatIds() == null || form.getSeatIds().size() == 0)){
                //传了，判断
                List<SeatInfo> seatInfos = seatsMap.get(form.getCinemaId());
                List<SeatInfo> newSeatInfos = new ArrayList<>();
                HashMap<Integer, SeatInfo> map = new HashMap<>();
                for (SeatInfo seatInfo : seatInfos) {
                    map.put(seatInfo.getSeatId(), seatInfo);
                }
                for (Integer seatInfoId : form.getSeatIds()) {
                    if (!map.keySet().contains(seatInfoId))
                        throw new MovieSessionException(MovieSessionExceptionCode.MOVIE_SESSION_HAVE_SEAT_NOT_FOUND);
                    newSeatInfos.add(map.get(seatInfoId));
                }
                //重新绑定座位信息
                seatsMap.put(form.getCinemaId(), newSeatInfos);
            }


            //电影
            Map<Integer, MovieInfo> movieInfoMap = new HashMap<>();
            for (MovieInfo movieInfo : movieInfos) {
                movieInfoMap.put(movieInfo.getMovieId(),movieInfo);
            }
            //自身时长,放映时间
            Date startTime = simpleFormat.parse(form.getSessionStarttime());
            Date endTime = simpleFormat.parse(form.getSessionEndtime());

            MovieInfo movieInfo = movieInfos.stream().filter(o -> o.getMovieId() == form.getMovieId()).collect(Collectors.toList()).get(0);
            Date downDate = simpleFormat.parse(movieInfo.getMovieDowndate());
            if (startTime.after(endTime) || startTime.before(new Date())
                    || endTime.after(downDate)
                    || ((endTime.getTime() - startTime.getTime()) <= movieInfo.getMovieTime() * 60 * 1000)){

                throw new MovieSessionException(MovieSessionExceptionCode.MOVIE_SESSION_TIME_ERROR);
            }

            //与数据库中场次判断冲突
            for (MovieSession movieSession : list1) {
                if (form.getCinemaId()!=movieSession.getCinemaId()) {
                    Date sessionStartTime = simpleFormat.parse(movieSession.getSessionStarttime());
                    Date sessionEndTime = simpleFormat.parse(movieSession.getSessionEndtime());
                    if (!(endTime.before(sessionStartTime)||startTime.after(sessionEndTime))) throw new MovieSessionException(MovieSessionExceptionCode.MOVIE_SESSION_HAVE_TIME_CONFLICT);
                }
            }
            MovieSession movieSession = BeanUtil.toBean(form, MovieSession.class);
            movieSession.setSessionStatus(StateUtil.MOVIE_SESSION_STATE_DISABLED);
            movieSession.setMovieName(movieInfoMap.get(form.getMovieId()).getMovieName());
            movieSession.setCinemaName(cinemaMap.get(form.getCinemaId()).getCinemaName());
            movieSessionMapper.insert(movieSession);
            //生成票务信息
            ArrayList<SessionTicket> sessionTickets = new ArrayList<>();
            for (SeatInfo seatInfo : seatsMap.get(form.getCinemaId())) {
                SessionTicket sessionTicket = new SessionTicket();
                sessionTicket.setSessionId(movieSession.getSessionId());
                sessionTicket.setTicketState(StateUtil.SESSION_TICKET_STATE_NOMAL);
                sessionTicket.setSeatId(seatInfo.getSeatId());
                sessionTicket.setSeatCol(seatInfo.getSeatCol());
                sessionTicket.setSeatRow(seatInfo.getSeatRow());
                sessionTickets.add(sessionTicket);
            }

            sessionTicketService.saveBatch(sessionTickets);
        }





    }

    @Override
    public PageInfo<MovieSession> load(MovieSessionParam param) {
        PageHelper.startPage(param.getPageNum()==null?1:param.getPageNum(),param.getPageSize()==null?6:param.getPageSize());
        QueryWrapper<MovieSession> q = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(param.getDate())) q.like("session_starttime",param.getDate());
        if (ObjectUtil.isNotEmpty(param.getMovieId())) q.eq("movie_id",param.getMovieId());
        if (ObjectUtil.isNotEmpty(param.getCinemaId())) q.eq("cinema_id",param.getCinemaId());
        if (ObjectUtil.isNotEmpty(param.getState())) q.eq("session_status",param.getState());

        List<MovieSession> movieSessions = this.list(q);
        PageInfo<MovieSession> pageInfo = new PageInfo<>(movieSessions);
        return pageInfo;
    }

    @Override
    @Transactional
    public void change(MovieSessionChangeParam param) throws Exception{
        Set<Integer> collect = param.getSessionIds().stream().collect(Collectors.toSet());
        ArrayList<Integer> sessionIds = new ArrayList<>(collect);
        List<MovieSession> sessions = this.list(new QueryWrapper<MovieSession>().in("session_id", sessionIds));
        if (sessions==null||sessions.size()<sessionIds.size()) throw new MovieSessionException(MovieSessionExceptionCode.MOVIE_SESSION_HAVE_SESSION_NOT_FOUND);
        List<MovieSession> collect1 = sessions.stream().filter(o -> o.getSessionStatus() == param.getState()).collect(Collectors.toList());
        if (collect1.size()!=0) throw new MovieSessionException(MovieSessionExceptionCode.MOVIE_SESSION_HAVE_SESSION_STATE_ERROR);
        Map<Integer, List<SessionTicket>> ticketMap = new HashMap<>();
        if (param.getState()==StateUtil.MOVIE_SESSION_STATE_NORMAL){
            QueryWrapper<SessionTicket> q = new QueryWrapper<>();
            List<SessionTicket> tickets = sessionTicketMapper.selectList(q.in("session_id", sessionIds));

            for (SessionTicket ticket : tickets) {
                List<SessionTicket> sessionTickets = ticketMap.get(ticket.getSessionId());
                if (sessionTickets==null) sessionTickets=new ArrayList<>();
                sessionTickets.add(ticket);
                ticketMap.put(ticket.getSessionId(),sessionTickets);
            }
            redisUtil.saveObject(RedisKeyUtil.sessionTickets(),ticketMap);
            this.update(new UpdateWrapper<MovieSession>().set("session_status",param.getState()).in("session_id",ticketMap.keySet()));

        }
        else {
            Map<Integer, List<SessionTicket>> map = (Map<Integer, List<SessionTicket>>) redisUtil.getObject(RedisKeyUtil.sessionTickets());
            System.out.println(map);
//            ArrayList<SessionTicket> sessionTickets = new ArrayList<>();
//            for (Integer integer : map.keySet()) {
//                List<SessionTicket> sessionTickets1 = map.get(integer);
//                sessionTickets.addAll(sessionTickets1);
//            }
//            sessionTicketService.updateBatchById(sessionTickets);
            ArrayList<String> strings = new ArrayList<>();
            strings.add(RedisKeyUtil.sessionTickets());
            redisUtil.del(strings);
            this.update(new UpdateWrapper<MovieSession>().set("session_status",param.getState()).in("session_id",map.keySet()));

        }

    }

    @Override
    public  void test() throws Exception{
        HashMap<Integer, List<Integer>> map = new HashMap<>();
        for (int i=0;i<5;i++){
            ArrayList<Integer> list = new ArrayList<>();
            for (int j=0;j<3;j++){
                list.add(i);
            }
            map.put(i,list);
            System.out.println(123);
        }
        redisUtil.saveObject("ll",map);
    }

    public static void main(String[] args) {
            int x=1,y=2,z=3;
        System.out.println(y>z^x!=z);
    }
}
